package com.anlogic.sdk.linker.ui;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

import org.apache.logging.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;

import com.anlogic.sdk.linker.LScript;
import com.anlogic.sdk.utils.LogUtils;

public class LinkerEditor extends FormEditor implements IResourceChangeListener {
	private Logger logger = LogUtils.getLogger(LinkerEditor.class);

	private TextEditor textEditor;

	private LinkerViewer linkerViewer;

	private boolean dirty = false;

	private LScript lscript;

	private String originalLscript;

	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		if (!(input instanceof IFileEditorInput))
			throw new PartInitException("Invalid Input: Must be IFileEditorInput");
		this.linkerViewer = new LinkerViewer(this, "overview_id", "Overview");
		this.lscript = new LScript();
		super.init(site, input);
	}

	@Override
	protected void addPages() {
		try {
			addPage((IFormPage) this.linkerViewer);
			this.textEditor = new TextEditor();
			int index = addPage((IEditorPart) this.textEditor, getEditorInput());
			setPageText(index, "Source");
		} catch (PartInitException e) {
			e.printStackTrace();
		}
	}

	private void initLscriptEditorPage() {
		this.logger.info("Read linker script...");
		IFile f = ((IFileEditorInput) getEditorInput()).getFile();
		try {
			this.originalLscript = getFileContentsAsString(f.getContents(true));
		} catch (IOException e) {
			this.logger.error("Unexpected error while reading linker script: {}", e.getMessage());
		} catch (CoreException e) {
			this.logger.error("Unexpected error while reading linker script: {}", e.getMessage());
		}
		this.lscript.parseString(this.originalLscript);
		linkerViewer.setModel(lscript, LinkerEditor.this);
		this.logger.info("Read linker script done");
	}

	private String getFileContentsAsString(InputStream is) throws IOException {
		StringBuilder sb = new StringBuilder();
		Scanner scanner = new Scanner(is);
		try {
			while (scanner.hasNextLine())
				sb.append(String.valueOf(scanner.nextLine()) + "\n");
		} finally {
			scanner.close();
		}
		return sb.toString();
	}

	@Override
	protected void setInput(IEditorInput input) {
		super.setInput(input);
		setPartName(getEditorInput().getName());
		initLscriptEditorPage();
	}

	@Override
	public boolean isDirty() {
		if (super.isDirty())
			return true;
		return this.dirty;
	}

	public void fireDirty() {
		if (!this.dirty) {
			this.dirty = true;
			this.editorDirtyStateChanged();
		}
	}

	@Override
	public void doSave(IProgressMonitor monitor) {
		this.logger.info("Save linker script...");
		this.textEditor.doSave(monitor);
		IFile f = ((IFileEditorInput) getEditorInput()).getFile();
		String contents = this.lscript.toString(this.originalLscript);
		if (getActivePage() == 1) {
			initLscriptEditorPage();
		} else if (!contents.equals(this.originalLscript)) {
			try {
				f.setContents(new ByteArrayInputStream(contents.getBytes()), 3, monitor);
				this.originalLscript = contents;
			} catch (CoreException e) {
				this.logger.error("Exception while save linker script: {}", e.getMessage());
			}
		}
		this.dirty = false;
		this.editorDirtyStateChanged();
		this.logger.info("Save linker script done");
	}

	@Override
	public void doSaveAs() {
		this.textEditor.doSaveAs();
	}

	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	@Override
	public void resourceChanged(IResourceChangeEvent event) {
		IFile f = ((IFileEditorInput) LinkerEditor.this.getEditorInput()).getFile();
		if (!f.exists()) {
			ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
			this.close(false);
		} else {
			this.initLscriptEditorPage();
			this.editorDirtyStateChanged();
		}
	}
}
